#include<map>
#include<cstdio>
#include<vector>
#include<signal.h>
#include"OnlineUser.hpp"
#include "udpsever.hpp"

using namespace std;
using namespace udpsever;

// void HandlerMessage(int sock,string& message,string&ip,uint16_t port) //处理方法1
// {
//     cout<<ip<<" : "<<port<<"----"<<message<<endl;  //打印收到的消息及相关信息.
//     //加工一下
//     string response = "response : ";
//     response+=message;
//     struct sockaddr_in goal ;
//     goal.sin_family = AF_INET;
//     goal.sin_port=htons(port);
//     goal.sin_addr.s_addr = inet_addr(ip.c_str());
//     int n = sendto(sock,response.c_str(),response.size(),0,(struct sockaddr*)&goal,sizeof goal);
//     if(n==-1)
//     {
//         cerr<<"sendto call failed";
//         exit(SENDTO_ERR);
//     }
// }

// #define DICTNAME "CH_ENG_dict"

// static map<string,string> dict;
// //初始化词典
// void init_dict(int)
// {
//     FILE* pf = fopen(DICTNAME,"r");
//     if(pf==nullptr)
//     {
//         cerr<<"open failed"<<endl;
//         exit(OPEN_ERR);
//     }
//     //读取一行数据
//     char buf[1024];
//     while(fgets(buf,sizeof buf,pf)!=0)
//     {
//         string str = buf;
//         int n = str.find(':');
//         string eng=str.substr(0,n);
//         string chn = str.substr(n);
//         dict.emplace(eng,chn);
//     }
//     fclose(pf);
// }

// //业务处理逻辑
// void HandlerMessage(int sock, string &message, string &ip, uint16_t port) // 处理方法2
// {
//     cout<<"receive : "<<message<<endl;
//     string response;
//     if(dict.find(message)==dict.end())
//     {
//         response="unknow";
//     }
//     else
//     response = dict[message];

//     struct sockaddr_in client;
//     client.sin_family=AF_INET;
//     client.sin_addr.s_addr=inet_addr(ip.c_str());
//     client.sin_port=htons(port);
//     sendto(sock,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof client);
// }

static OnlineUser OnlineUSR;
void HandlerMessage(int sock,string& message ,string& ip ,uint16_t port)
{
    string response;
    if(message == "Online" && !OnlineUSR.isonline(ip,port)) //上线请求
    {
        OnlineUSR.addusr(ip,port);
        string id=ip+":";
        id+=to_string(port);
        //给其他客户端发送消息提示我们的用户上线
        string toothers = id+"has onlined";
        for(const auto& usr:OnlineUSR._usrs)
        {
            if(usr.first!=id)
            {
                struct sockaddr_in goal;
                goal.sin_family=AF_INET;
                goal.sin_port = htons((usr.second).second);
                goal.sin_addr.s_addr=inet_addr((usr.second).first.c_str());
                //发送当前用户上线的消息
                sendto(sock,toothers.c_str(),toothers.size(),0,(struct sockaddr*)&goal,sizeof(goal));
            }
        }
        //向上线的用户发送成功上线的提示
        response = "Online Success";
        struct sockaddr_in client;
        client.sin_family=AF_INET;
        client.sin_addr.s_addr=inet_addr(ip.c_str());
        client.sin_port=htons(port);
        sendto(sock,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof client);
        return;
    }
    else if(message == "Online" && OnlineUSR.isonline(ip,port)) //上线请求重复
    {
        response = "repeat Online";
        struct sockaddr_in client;
        client.sin_family=AF_INET;
        client.sin_addr.s_addr=inet_addr(ip.c_str());
        client.sin_port=htons(port);
        sendto(sock,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof client);
        return;
    }
    if(message == "Offline") //下线请求，不考虑是否在线
    {
        response = "Offline success";
        OnlineUSR.delusr(ip,port);
        struct sockaddr_in client;
        client.sin_family=AF_INET;
        client.sin_addr.s_addr=inet_addr(ip.c_str());
        client.sin_port=htons(port);
        sendto(sock,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof client);
    }
    if(OnlineUSR.isonline(ip,port)) //在线
    {
        //向除他之外的所有用户广播消息
        for(const auto& usr:OnlineUSR._usrs)
        {
            string id =ip+":";
            id+=to_string(port);
            if(usr.first !=id)
            {
                struct sockaddr_in goal;
                goal.sin_family=AF_INET;
                goal.sin_port = htons((usr.second).second);
                goal.sin_addr.s_addr=inet_addr((usr.second).first.c_str());
                //发送当前用户上线的消息
                sendto(sock,message.c_str(),message.size(),0,(struct sockaddr*)&goal,sizeof(goal));
            }
        }
    }
    else
    {
        //提示该用户未上线
        response = "Please Online First";
        struct sockaddr_in client;
        client.sin_family=AF_INET;
        client.sin_addr.s_addr=inet_addr(ip.c_str());
        client.sin_port=htons(port);
        sendto(sock,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof client);
        return;
    }
    
}




// //命令行业务逻辑
// void HandlerMessage(int sock,string&message,string&ip,uint16_t port)
// {
//     cout<<"receive a command :" <<message<<endl;
//     string response;
//     struct sockaddr_in client;
//     client.sin_addr.s_addr=inet_addr(ip.c_str());
//     client.sin_family=AF_INET;
//     client.sin_port=htons(port);
//     vector<string> ban ={"rm","mv"};
//     for(auto&str:ban)
//     {
//         if(message.find(str)!=string::npos)
//         {
//             response = "Unsafe operation";
//             sendto(sock,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof client);
//             return;
//         }
//     }
//     FILE*pf=popen(message.c_str(),"r");
//     char result[1024];
//     while(fgets(result,sizeof result , pf)!=0)
//     {
//         response+= result;       
//     }    
//     sendto(sock,response.c_str(),response.size(),0,(struct sockaddr*)&client,sizeof client);
// }


// 使用手册
void Usage()
{
    cout << endl
         << "Usage:" << endl
         << "./sever ip port" << endl;
}
int main(int argc, char *argv[])
{
    // ./sever port
    if (argc != 2)
    {
        Usage();
        exit(USAGE_ERR);
    }
    // signal(2,init_dict);
    // init_dict(0);
    uint16_t port = (uint16_t)atoi(argv[1]);
    sever sv(port, HandlerMessage);
    sv.init();
    sv.start();
    return 0;
}
